﻿#include "ZhConvertclass.h"
#include <qsciscintilla.h>

#include "ZHConvertUtils.h"
#include "BoyerMooreU.h"

#include <QMessageBox>
#include <string>
#include <locale>
#include <codecvt>
#include <QTextCodec>
#include <QProcess>
#include <Shlwapi.h>
#include "Windows.h"
#include "Scintilla.h"


NodeList* strList = nullptr;
const wchar_t* STradFix = TEXT("./plugin/SipTradFix.txt");

// 判断文件是否存在
bool isFileExists_ifstream(string& name) {

	ifstream fin(name.c_str());
	return fin.good();
}

// convert string to wstring
inline std::wstring to_wide_string(const std::string& input)
{
	std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
	return converter.from_bytes(input);
}
// convert wstring to string 
inline std::string to_byte_string(const std::wstring& input)
{
	std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
	return converter.to_bytes(input);
}

void ConvertTableInit()
{
	size_t f;
	string file = to_byte_string(STradFix);
	if (isFileExists_ifstream(file))
	{
		strList = ReadConvertTable(file.c_str(), f);//读取转换校正表
	}
	else
	{
		strList = nullptr;
	}
}

void ConvertTableCleanUp()
{
	for (size_t i = strList->size() - 1; i > 0; i--)
		delete (*strList)[i];
	delete[](*strList)[0]->simp;
	strList->clear();
}

ZhConvertClass::ZhConvertClass(QWidget* mainWidget, const QString& pluginPath, QsciScintilla* pEdit, QObject* parent)
	: QObject(parent)
{
	ConvertTableInit();
}

ZhConvertClass::~ZhConvertClass()
{
	if (strList != nullptr)
	{
		ConvertTableCleanUp();
	}
}


wchar_t* multiByteToWideChar(const string& pKey)
{
	const char* pCStrKey = pKey.c_str();
	//第一次调用返回转换后的字符串长度，用于确认为wchar_t*开辟多大的内存空间
	int pSize = MultiByteToWideChar(CP_OEMCP, 0, pCStrKey, strlen(pCStrKey) + 1, NULL, 0);
	wchar_t* pWCStrKey = new wchar_t[pSize];
	//第二次调用将单字节字符串转换成双字节字符串
	MultiByteToWideChar(CP_OEMCP, 0, pCStrKey, strlen(pCStrKey) + 1, pWCStrKey, pSize);
	return pWCStrKey;
}
char * wchar2char(const wchar_t* wchar)
{
	char * m_char;
	int len = WideCharToMultiByte(CP_ACP, 0, wchar, wcslen(wchar), NULL, 0, NULL, NULL);
	m_char = new char[len + 1];
	WideCharToMultiByte(CP_ACP, 0, wchar, wcslen(wchar), m_char, len, NULL, NULL);
	m_char[len] = '\0';
	return m_char;
}

wchar_t * char2wchar(const char* cchar)
{
	wchar_t *m_wchar;
	int len = MultiByteToWideChar(CP_ACP, 0, cchar, strlen(cchar), NULL, 0);
	m_wchar = new wchar_t[len + 1];
	MultiByteToWideChar(CP_ACP, 0, cchar, strlen(cchar), m_wchar, len);
	m_wchar[len] = '\0';
	return m_wchar;
}


char* UTF8ToGBK(const char* strUTF8)
{
	int len = MultiByteToWideChar(CP_UTF8, 0, strUTF8, -1, NULL, 0);
	wchar_t* wszGBK = new wchar_t[len + 1];
	memset(wszGBK, 0, len * 2 + 2);
	MultiByteToWideChar(CP_UTF8, 0, strUTF8, -1, wszGBK, len);
	len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);
	char* szGBK = new char[len + 1];
	memset(szGBK, 0, len + 1);
	WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL);
	if (wszGBK) delete[] wszGBK;
	return szGBK;
}
char* GBKToUTF8(const char* strGBK)
{
	int len = MultiByteToWideChar(CP_ACP, 0, strGBK, -1, NULL, 0);
	wchar_t* wstr = new wchar_t[len + 1];
	memset(wstr, 0, len + 1);
	MultiByteToWideChar(CP_ACP, 0, strGBK, -1, wstr, len);
	len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
	char* str = new char[len + 1];
	memset(str, 0, len + 1);
	WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
	if (wstr) delete[] wstr;
	return str;
}


string SimpletoTra(const string& _str)
{
	LPCSTR lpSrcStr = _str.c_str();
	int cchSrc = static_cast<int>(_str.size());
	int cchDest = static_cast<int>(1 + _str.size());
	LPSTR lpDestStr = new CHAR[cchDest]{ 0 };
	LCMapStringA(0x0804, LCMAP_TRADITIONAL_CHINESE, lpSrcStr, cchSrc, lpDestStr, cchDest);
	string str(lpDestStr);
	delete lpDestStr;
	lpDestStr = nullptr;
	return str;
}


char*  SimpletoTraC(const string& _str)
{
	LPCSTR lpSrcStr = _str.c_str();
	int cchSrc = static_cast<int>(_str.size());
	int cchDest = static_cast<int>(1 + _str.size());
	LPSTR lpDestStr = new CHAR[cchDest]{ 0 };
	LCMapStringA(0x0804, LCMAP_TRADITIONAL_CHINESE, lpSrcStr, cchSrc, lpDestStr, cchDest);
	return lpDestStr;
}


string TraToSimple(const string& _str)
{
	LPCSTR lpSrcStr = _str.c_str();
	int cchSrc = static_cast<int>(_str.size());
	int cchDest = static_cast<int>(1 + _str.size());
	LPSTR lpDestStr = new CHAR[cchDest]{ 0 };
	LCMapStringA(0x0804, LCMAP_SIMPLIFIED_CHINESE, lpSrcStr, cchSrc, lpDestStr, cchDest);
	string str(lpDestStr);
	delete lpDestStr;
	lpDestStr = nullptr;
	return str;

}

char* TraToSimpleC(const string& _str)
{
	LPCSTR lpSrcStr = _str.c_str();
	int cchSrc = static_cast<int>(_str.size());
	int cchDest = static_cast<int>(1 + _str.size());
	LPSTR lpDestStr = new CHAR[cchDest]{ 0 };
	LCMapStringA(0x0804, LCMAP_SIMPLIFIED_CHINESE, lpSrcStr, cchSrc, lpDestStr, cchDest);
	string str(lpDestStr);
	return lpDestStr;

}


void ZhConvertClass::on_TraToSimple()
{
	auto scintilla_ = scintillaCallback_();
	intext_ = scintilla_->text();
	if (intext_.isEmpty())
	{
		return;
	}
	QString textOutput;
	int selectTextLen;
	const int buflen = scintilla_->length() + 1;
	
	char* buf = new char[buflen];
	char* tmp = new char[buflen];
	if (buf)
	{
		selectTextLen = scintilla_->SendScintilla(SCI_GETSELECTIONEND) - scintilla_->SendScintilla(SCI_GETSELECTIONSTART);
		if (selectTextLen == 0)
		{
			scintilla_->SendScintilla(SCI_GETTEXT, buflen, buf);
		}
		else
		{
			scintilla_->SendScintilla(SCI_GETSELTEXT, buf);
		}
	}
	//QTextCodec::setCodecForLocale(QTextCodec::codecForName("GBK"));
	tmp = UTF8ToGBK(buf);
	//const char* simple = "简体中文,你好中国";
	buf = TraToSimpleC(tmp);

	tmp = GBKToUTF8(buf);
	if (selectTextLen == 0)
	{
		scintilla_->SendScintilla(SCI_SETTEXT, tmp);
	}
	else
	{
		scintilla_->SendScintilla(SCI_REPLACESEL, tmp);
	}
	delete[] tmp;
	delete[] buf;

}


void ZhConvertClass::on_SimpletoTra()
{
	auto scintilla_ = scintillaCallback_();
	intext_ = scintilla_->text();
	if (intext_.isEmpty())
	{
		return;
	}
	QString textOutput;
	int selectTextLen, nTextLen;
	const int buflen = scintilla_->length() + 1;
	char* buf = new char[buflen];
	char* tmp = new char[buflen];
	if (buf)
	{
		selectTextLen = scintilla_->SendScintilla(SCI_GETSELECTIONEND) - scintilla_->SendScintilla(SCI_GETSELECTIONSTART);
		if (selectTextLen == 0)
		{
			nTextLen = scintilla_->SendScintilla(SCI_GETTEXTLENGTH);
			scintilla_->SendScintilla(SCI_GETTEXT, buflen, buf);
		}
		else
		{
			nTextLen = selectTextLen;
			scintilla_->SendScintilla(SCI_GETSELTEXT, buf);
		}
	}

	QTextCodec::setCodecForLocale(QTextCodec::codecForName("GBK"));
	tmp = UTF8ToGBK(buf);
	//const char* simple = "简体中文,你好中国";

	buf = SimpletoTraC(tmp);

	string file = to_byte_string(STradFix);
	if (strList != nullptr)
	{
		int len;
		wchar_t* result = new wchar_t[nTextLen];
		result = char2wchar(buf);
		wchar_t* pat; wchar_t* rep;

		for (size_t i = 0; i < strList->size(); i++)//进行校正
		{
			pat = (*strList)[i]->simp;
			rep = (*strList)[i]->trad;
			len = (*strList)[i]->Len;
			replace(result, nTextLen, pat, len, rep);
		}
		buf = wchar2char(result);
		delete[] result;
	}
	tmp = GBKToUTF8(buf);
	if (selectTextLen == 0)
	{
		scintilla_->SendScintilla(SCI_SETTEXT, tmp);
	}
	else
	{
		scintilla_->SendScintilla(SCI_REPLACESEL, tmp);
	}
	delete[] tmp;
	delete[] buf;
}

void ZhConvertClass::on_OpenTradFix()
{	
	string file = to_byte_string(STradFix);

	if (!isFileExists_ifstream(file))
	{
		QMessageBox::warning(NULL, "Warning", "Error Message: file not exist, Plaese cpoy SipTradFix.txt to  plugin folder");
		return;
	}
	else
	{
		QProcess process;
		QString filePath = QString::fromStdString(file);;
		filePath.replace("/", "\\"); // 只能识别 "\"
		QString cmd = QString("explorer.exe /select,\"%1\"").arg(filePath);
		process.startDetached(cmd);
	}

}

void ZhConvertClass::on_ChangeFix()
{
	auto scintilla_ = scintillaCallback_();
	intext_ = scintilla_->text();
	if (intext_.isEmpty())
	{
		return;
	}
	int selectTextLen, nTextLen;
	const int buflen = scintilla_->length() + 1;
	char* buf = new char[buflen];
	selectTextLen = scintilla_->SendScintilla(SCI_GETSELECTIONEND) - scintilla_->SendScintilla(SCI_GETSELECTIONSTART);
	if (selectTextLen == 0)
	{
		scintilla_->SendScintilla(SCI_GETTEXT, buflen, buf);
	}
	else
	{
		scintilla_->SendScintilla(SCI_GETSELTEXT, buf);
	}
	buf = UTF8ToGBK(buf);
	if (strList != nullptr)
	{
		int len;
		wchar_t* result = new wchar_t[buflen];
		result = char2wchar(buf);
		wchar_t* pat; wchar_t* rep;

		for (size_t i = 0; i < strList->size(); i++)//进行校正
		{
			pat = (*strList)[i]->simp;
			rep = (*strList)[i]->trad;
			len = (*strList)[i]->Len;
			replace(result, buflen, pat, len, rep);
		}
		buf = wchar2char(result);
		delete[] result;
	}
	buf = GBKToUTF8(buf);
	if (selectTextLen == 0)
	{
		scintilla_->SendScintilla(SCI_SETTEXT, buf);
	}
	else
	{
		scintilla_->SendScintilla(SCI_REPLACESEL, buf);
	}
	

}

void ZhConvertClass::setScintilla(const std::function<QsciScintilla* ()>& cb)
{
	scintillaCallback_ = cb;
}

